package call

import (
	"time"

	"go.opentelemetry.io/otel/trace"
	"greatestworks/aop/logging"
	"greatestworks/aop/logtype"
	"greatestworks/aop/traceio"
)

// ClientOptions are the options to configure an RPC client.
type ClientOptions struct {
	// Load balancer. Defaults to RoundRobin() if nil.
	Balancer Balancer

	// Logger. Defaults to a logger that logs to stderr.
	Logger logtype.Logger

	// If non-zero, each call will optimistically spin for a given duration
	// before blocking, waiting for the results.
	OptimisticSpinDuration time.Duration

	// If non-zero, all writes smaller than this limit are flattened into
	// a single buffer before being written on the connection.
	WriteFlattenLimit int
}

// ServerOption are the options to configure an RPC server.
type ServerOptions struct {
	// Logger. Defaults to a logger that logs to stderr.
	Logger logtype.Logger

	// Tracer. Defaults to a discarding tracer.
	Tracer trace.Tracer

	// If non-zero, calls on the server are inlined and a new goroutine is
	// launched only if the call takes longer than the provided duration.
	InlineHandlerDuration time.Duration

	// If non-zero, all writes smaller than this limit are flattened into
	// a single buffer before being written on the connection.
	WriteFlattenLimit int
}

// CallOptions are call-specific options.
type CallOptions struct {
	// ShardKey, if not 0, is the shard key that a Balancer can use to route a
	// call. A Balancer can always choose to ignore the ShardKey.
	//
	// TODO(mwhittaker): Figure out a way to have 0 be a valid shard key. Could
	// change to *uint64 for example.
	ShardKey uint64

	// Balancer, if not nil, is the Balancer to use for a call, instead of the
	// Balancer that the client was constructed with (provided in
	// ClientOptions).
	Balancer Balancer
}

// withDefaults returns a copy of the ClientOptions with zero values replaced
// with default values.
func (c ClientOptions) withDefaults() ClientOptions {
	if c.Logger == nil {
		c.Logger = logging.StderrLogger(logging.Options{})
	}
	return c
}

// withDefaults returns a copy of the ServerOptions with zero values replaced
// with default values.
func (s ServerOptions) withDefaults() ServerOptions {
	if s.Logger == nil {
		s.Logger = logging.StderrLogger(logging.Options{})
	}
	if s.Tracer == nil {
		s.Tracer = traceio.TestTracer()
	}
	return s
}
